#include "FlashDriver.h"
#include "DSP2833x_Device.h"
#include "UARTDriverA.h"
#include <stdio.h>
#include <math.h>

extern UARTDriverA uartDriverA;

bool FlashDriver::Init() 
{
	EALLOW;
	// 1. GPIO
	GpioCtrlRegs.GPBPUD.bit.GPIO54 = 0;   // Enable pull-up on GPIO54 (SPISIMOA)
    GpioCtrlRegs.GPBPUD.bit.GPIO55 = 0;   // Enable pull-up on GPIO55 (SPISOMIA)
    GpioCtrlRegs.GPBPUD.bit.GPIO56 = 0;   // Enable pull-up on GPIO56 (SPICLKA)
    GpioCtrlRegs.GPBQSEL2.bit.GPIO54 = 3; // Asynch input GPIO54 (SPISIMOA)
	GpioCtrlRegs.GPBQSEL2.bit.GPIO55 = 3; // Asynch input GPIO55 (SPISOMIA)
	GpioCtrlRegs.GPBQSEL2.bit.GPIO56 = 3; // Asynch input GPIO56 (SPICLKA)
	GpioCtrlRegs.GPBMUX2.bit.GPIO54 = 1; // Configure GPIO54 as SPISIMOA
	GpioCtrlRegs.GPBMUX2.bit.GPIO55 = 1; // Configure GPIO55 as SPISOMIA
	GpioCtrlRegs.GPBMUX2.bit.GPIO56 = 1; // Configure GPIO56 as SPICLKA

	GpioCtrlRegs.GPBPUD.bit.GPIO53 = 0;   // Enable pull-up on GPIO50 (MEMORYCS)
	GpioCtrlRegs.GPBMUX2.bit.GPIO53 = 0; // configure MEMORYCS as GPIO
	GpioDataRegs.GPBSET.bit.GPIO53 = 1; // deselect
	GpioCtrlRegs.GPBDIR.bit.GPIO53 = 1; // configure MEMORYCS as output
	
	EDIS;

	SetupSPI();

	// read ID
	char idBuffer[20];
	ReadID(idBuffer);
	char tmp[100];
	sprintf(tmp, "MEMORY ID:%02X:%02X:%02X:%02X:%02X\r\n", idBuffer[0], idBuffer[1], idBuffer[2], idBuffer[3], idBuffer[4]);
	uartDriverA.SendData(tmp);

	return true;	
}

void FlashDriver::SetupSPI()
{
	// configure SPI, clock =  Clock = 37.5Mhz/10 = 3.75Mhz, 8 bit, Master Mode
	SpiaRegs.SPICCR.all =0x0047;	             // Reset on, falling edge (polarity = 1), 8-bit char bits  
	SpiaRegs.SPICTL.all =0x0006;    		     // Enable master mode, normal phase (phase = 0), enable talk, and SPI int disabled.
	SpiaRegs.SPIBRR =0x0009;	// 37.6MHz/10									
    SpiaRegs.SPICCR.all =0x00C7;		         // Relinquish SPI from Reset   
    SpiaRegs.SPIPRI.bit.FREE = 1;                // Set so breakpoints don't disturb xmission
}

unsigned char FlashDriver::WriteByte(unsigned char data)
{
	Uint16 rw = (data << 8); // left justify
	SpiaRegs.SPITXBUF=rw; // send data
	
	//wait for end of transfer
	while( SpiaRegs.SPISTS.bit.INT_FLAG != 1 );
	// read data
	unsigned char rd = SpiaRegs.SPIRXBUF & 0x00FF;

	return rd;
}

void FlashDriver::ReadID(char* buffer)
{
	GpioDataRegs.GPBCLEAR.bit.GPIO53 = 1; // select
	WriteByte(0x9F); // write RDID instruction
	for(int i=0; i!=20; i++)
	{
   		buffer[i] = WriteByte(0x00); // read data
	}
	GpioDataRegs.GPBSET.bit.GPIO53 = 1; // deselect
}

void FlashDriver::WriteWREN()
{
	GpioDataRegs.GPBCLEAR.bit.GPIO53 = 1; // select
	WriteByte(0x06); // write WREN instruction	
	GpioDataRegs.GPBSET.bit.GPIO53 = 1; // deselect
}

void FlashDriver::BulkErase()
{
	WriteWREN();
	for(Uint32 i=0; i!=2000L; i++ ); // wait a little?!?!?!
	GpioDataRegs.GPBCLEAR.bit.GPIO53 = 1; // select
	WriteByte(0xC7); // write BE instruction
	GpioDataRegs.GPBSET.bit.GPIO53 = 1; // deselect
}

bool FlashDriver::IsReady()
{
	GpioDataRegs.GPBCLEAR.bit.GPIO53 = 1; // select	
	WriteByte(0x05); // write RDSR instruction
	unsigned char data = WriteByte(0x00); // read
	bool isReady = true;
	if( data & 0x01 ) isReady = false; // WIP (write in progress) is set
	GpioDataRegs.GPBSET.bit.GPIO53 = 1; // deselect	
	
	return isReady;
}

bool FlashDriver::WritePage(Uint32 address, unsigned char* buffer)
{
	if( !IsReady() ) return false; // not ready 
	WriteWREN();
	for(Uint32 i=0; i!=2000L; i++ ); // wait a little?!?!?!
	GpioDataRegs.GPBCLEAR.bit.GPIO53 = 1; // select	
	WriteByte(0x02); // write PP instruction
	// write address
	WriteByte((address>>16)&0x00FF); // highest byte first
	WriteByte((address>>8)&0x00FF); // med byte
	WriteByte((address)&0x00FF); // low byte	
	// write data
	for(int i=0; i!=256; i++ )
	{
		WriteByte(buffer[i]); // write data
	}
	GpioDataRegs.GPBSET.bit.GPIO53 = 1; // deselect	
	
	return true;		
}

void FlashDriver::ReadPage(Uint32 address, unsigned char* buffer)
{
	GpioDataRegs.GPBCLEAR.bit.GPIO53 = 1; // select	
	WriteByte(0x03); // write READ instruction
	// write address
	WriteByte((address>>16)&0x00FF); // highest byte first
	WriteByte((address>>8)&0x00FF); // med byte
	WriteByte((address)&0x00FF); // low byte
	// read data
	for(int i=0; i!=256; i++ )
	{
		buffer[i] = WriteByte(0x00); // read data
	}
	
	GpioDataRegs.GPBSET.bit.GPIO53 = 1; // deselect		
}

bool FlashDriver::WritePage16(Uint32 address, unsigned char* buffer)
{
	// convert 128 chars (16bit) to 256 chars (8 bit)
	unsigned char data[256]; 	
	for(int i=0; i!=128; i++)
	{
		data[(i*2)] = buffer[i] & 0x00FF; // low
		data[(i*2)+1] = (buffer[i] >> 8); // high byte
	}
	return WritePage(address, data);
}

void FlashDriver::ReadPage16(Uint32 address, unsigned char* buffer)
{
	unsigned char data[256]; 	
	ReadPage(address, data);
	for(int i=0; i!=128; i++)
	{
		buffer[i] = data[(i*2)];
		buffer[i] += (data[(i*2)+1]<<8);
	}	
}
